package cn.j0n4than.accountingtool.service.impl;

import cn.j0n4than.accountingtool.entity.Spending;
import cn.j0n4than.accountingtool.mapper.SpendingMapper;
import cn.j0n4than.accountingtool.service.SpendingService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.TemporalAdjusters;
import java.util.Date;
import java.util.List;

/**
 * 消费服务接口实现
 *
 * @author jonathan
 */
@Slf4j
@Service
public class SpendingServiceImpl extends ServiceImpl<SpendingMapper, Spending> implements SpendingService {

    /**
     * 插入数据
     *
     * @param spending Spending对象实例
     * @return 影响行数
     */
    @Override
    public Integer insert(Spending spending) {
        return baseMapper.insert(spending);
    }

    /**
     * 获取花费分页列表
     *
     * @param spending 消费实体对象,这里这是查询条件
     * @param page     页码
     * @param size     页数据
     * @return Page
     */
    @Override
    public Page<Spending> getPage(Spending spending, Integer page, Integer size) {
        Page<Spending> spendingPage = new Page<>(page, size);
        QueryWrapper<Spending> spendingQueryWrapper = this.conditions(spending, false);
        return this.baseMapper.selectPage(spendingPage, spendingQueryWrapper);
    }

    /**
     * 获取消费带类型信息的分页列表
     *
     * @param spending 消费实体对象
     *                 这里这是查询条件
     * @param page     页码
     * @param size     页数据
     * @return Page
     */
    @Override
    public Page<Spending> getPageWithType(Spending spending, Integer page, Integer size) {
        QueryWrapper<Spending> conditions = this.conditions(spending, true);
        conditions.orderByDesc("spent_at");
        Page<Spending> spendingPage = new Page<>(page, size);
        return this.baseMapper.getDataWithType(conditions, spendingPage);
    }

    /**
     * 获取近期消费
     *
     * @param userId 某个用户的
     * @param limit  获取数据条数
     * @return List
     */
    @Override
    public List<Spending> getTopData(Integer userId, Integer limit) {
        return baseMapper.getTopDataWithType(userId, limit);
    }

    /**
     * 获取消费金额
     *
     * @param spending 消费实体对象,这里这是查询条件
     * @return BigDecimal
     */
    @Override
    public BigDecimal getSpendingAmount(Spending spending) {
        QueryWrapper<Spending> spendingQueryWrapper = this.conditions(spending, false);
        spendingQueryWrapper.select("sum(amount) as sumAmount");
        Spending result = this.baseMapper.selectOne(spendingQueryWrapper);

        //防止空指针异常，查询结果没有数据的时候，result将为null
        if (result == null) {
            return new BigDecimal("0.00");
        }
        return result.sumAmount;
    }

    /**
     * 获取今日支出金额
     *
     * @param userId 用户ID
     * @return BigDecimal
     */
    @Override
    public BigDecimal getSpendingAmountToday(Integer userId) {
        Spending spending = new Spending();
        long startTime = LocalDate.now()
                //今日0点
                .atStartOfDay()
                .atZone(ZoneId.systemDefault())
                .toInstant()
                .toEpochMilli();
        spending.startTime = new Date(startTime);
        spending.userId = userId;
        return this.getSpendingAmount(spending);
    }


    /**
     * 获取本周支出金额
     *
     * @param userId 用户ID
     * @return BigDecimal
     */
    @Override
    public BigDecimal getSpendingAmountThisWeek(Integer userId) {
        Spending spending = new Spending();
        long startTime = LocalDate.now()
                //每周周一
                .with(DayOfWeek.of(1))
                .atStartOfDay()
                .atZone(ZoneId.systemDefault())
                .toInstant()
                .toEpochMilli();
        spending.startTime = new Date(startTime);
        spending.userId = userId;
        return this.getSpendingAmount(spending);
    }

    /**
     * 获取本月支出金额
     *
     * @param userId 用户ID
     * @return BigDecimal
     */
    @Override
    public BigDecimal getSpendingAmountThisMonth(Integer userId) {
        Spending spending = new Spending();

        long startTime = LocalDate.now()
                //每月一日
                .with(TemporalAdjusters.firstDayOfMonth())
                .atStartOfDay()
                .atZone(ZoneId.systemDefault())
                .toInstant()
                .toEpochMilli();

        spending.startTime = new Date(startTime);
        spending.userId = userId;
        return this.getSpendingAmount(spending);
    }

    /**
     * 查询条件(算是解藕吧)
     *
     * @param spending   条件内容
     * @param multiTable 我是撒比
     * @return QueryWrapper
     * @see SpendingServiceImpl 调用这个方法的 方法注释
     */
    private QueryWrapper<Spending> conditions(Spending spending, Boolean multiTable) {
        QueryWrapper<Spending> spendingQueryWrapper = new QueryWrapper<>();
        //条件...

        if (spending.userId != null) {
            if (multiTable) {
                spendingQueryWrapper.eq("spending.user_id", spending.userId);
            } else {
                spendingQueryWrapper.eq("user_id", spending.userId);
            }
        }

        //如果类型不为空，则把类型加入条件
        if (spending.typeId != null) {
            spendingQueryWrapper.eq("type_id", spending.typeId);
        }

        //时间段
        if (spending.startTime != null && spending.endTime != null) {
            spendingQueryWrapper.between("spent_at", spending.startTime, spending.endTime);
        }

        //从开始时间后的数据
        if (spending.startTime != null && spending.endTime == null) {
            spendingQueryWrapper.ge("spent_at", spending.startTime);
        }

        //结束时间之前的数据
        if (spending.startTime == null && spending.endTime != null) {
            spendingQueryWrapper.le("spent_at", spending.endTime);
        }

        return spendingQueryWrapper;
    }
}
